package com.aifund.app.service.impl;

import com.aifund.app.entity.form.regist.PhoneRegisterForm;
import com.aifund.app.entity.form.user.BindApiForm;
import com.aifund.app.entity.form.user.IntegrationCashForm;
import com.aifund.app.entity.form.user.ModifyInformationForm;
import com.aifund.app.entity.form.user.RequestExchangeManForm;
import com.aifund.app.entity.vo.LoginVo;
import com.aifund.app.entity.vo.PhoneRegisterVo;
import com.aifund.app.entity.vo.robot.GetExchangeManTacticsVo;
import com.aifund.app.entity.vo.user.MyAssetsVo;
import com.aifund.app.enums.MqExchangeEnum;
import com.aifund.app.enums.MqRoutingKeyEnum;
import com.aifund.app.service.*;
import com.aifund.app.util.InvitationCodeUtil;
import com.aifund.common.dao.UserDao;
import com.aifund.common.entity.*;
import com.aifund.common.enums.CommonEnum;
import com.aifund.common.enums.manTactics.TradeTypeEnum;
import com.aifund.common.enums.redis.RedisSetKey;
import com.aifund.common.enums.user.CashStatus;
import com.aifund.common.enums.user.ChargeEnum;
import com.aifund.common.enums.user.UserEnum;
import com.aifund.common.enums.vertify.ExchangeManTacticsStatusEnum;
import com.aifund.common.exception.AiFundException;
import com.aifund.common.result.ResultBody;
import com.aifund.common.service.SystemConfigService;
import com.aifund.common.util.RedisUtil;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author xiaolin
 */
@SuppressWarnings("AlibabaTransactionMustHaveRollback")
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    SystemConfigService configService;
    @Autowired
    PhoneCodeService phoneCodeService;
    @Autowired
    UserBindExchangeService userBindExchangeService;
    @Autowired
    ExchangeService exchangeService;
    @Autowired
    SystemConfigService systemConfigService;
    @Autowired
    UserCashService userCashService;
    @Autowired
    ChargeService chargeService;
    @Autowired
    UserInvitationService userInvitationService;
    @Autowired
    ExchangeManTacticsService exchangeManTacticsService;
    @Autowired
    FollowOrderManTacticsService followOrderManTacticsService;
    @Autowired
    TacticsTransactionCurrencyService tacticsTransactionCurrencyService;
    @Autowired
    RabbitTemplate rabbitTemplate;


    @Override
    public ResultBody<LoginVo> loginByPhoneAndPwd(String phone, String pwd) {
        AiUser aiUser = userDao.getByPhoneAndAiPassword(phone, pwd);
        if(aiUser == null){
            throw new AiFundException("400","用户名不存在或密码错误");
        }
        String token = creatToken(aiUser.getId(),new Date());
        TokenEntity tokenEntity = new TokenEntity();
        tokenEntity.setAiUserId(aiUser.getId());
        tokenEntity.setToken(creatToken(aiUser.getId(),new Date()));
        if(!redisUtil.hset(RedisSetKey.USER_TOKEN.getSetKey(),aiUser.getId()+"",tokenEntity)){
            throw new AiFundException("500","服务器异常","用户token保存失败");
        }
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setHeader(aiUser.getHeader());
        loginVo.setNickName(aiUser.getNickName());
        loginVo.setVipLever(aiUser.getVipLever());
        ResultBody<LoginVo> resultBody = ResultBody.success();
        resultBody.setResult(loginVo);
        return resultBody;
    }

    @Override
    public ResultBody loginByEmailAndPwd(String email, String pwd) {
        AiUser aiUser = userDao.getByEmailAndAiPassword(email, pwd);
        if(aiUser == null){
            throw new AiFundException("400","邮箱不存在或密码错误");
        }
        String token = creatToken(aiUser.getId(),new Date());
        TokenEntity tokenEntity = new TokenEntity();
        tokenEntity.setAiUserId(aiUser.getId());
        tokenEntity.setToken(token);
        if(!redisUtil.hset(RedisSetKey.USER_TOKEN.getSetKey(),aiUser.getId()+"",tokenEntity)){
            throw new AiFundException("500","服务器异常","用户token保存失败");
        }
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        ResultBody<LoginVo> resultBody = ResultBody.success();
        resultBody.setResult(loginVo);
        return resultBody;
    }

    @Override
    public BigDecimal getIntegration(Long userId) {
        AiUser aiUser = userDao.getById(userId);
        BigDecimal integration = aiUser.getIntegration();
        return integration;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void integrationCash(IntegrationCashForm cashForm,Long userId) {
        AiUser user = userDao.getById(userId);
        //用户积分
        BigDecimal integration = user.getIntegration();
        if(integration==null){
            throw new AiFundException("500","积分不足");
        }
        if(integration.compareTo(user.getIntegration()) == 1){
            throw new AiFundException("500","积分不足");
        }


        //最小提币数量
        BigDecimal minCashNum = systemConfigService.getMinCashNum();
        //最小提币手续费
        BigDecimal minCashHandlingFee = systemConfigService.getMinCashHandlingFee();
        //最大提币手续费
        BigDecimal maxCashHandlingFee = systemConfigService.getMaxCashHandlingFee();
        //提币手续费百分比
        BigDecimal cashPercentage = systemConfigService.getCashPercentage();

        if(cashForm.getCashNum().compareTo(minCashNum) == -1){
            throw new AiFundException("500","最小提币数量为"+minCashNum);
        }

        /**
         * 计算手续费
         */
        BigDecimal multiply = cashForm.getCashNum().multiply(cashPercentage);
        if(multiply.compareTo(minCashHandlingFee) == -1){
            multiply = minCashHandlingFee;
        }
        if(multiply.compareTo(minCashHandlingFee) == 1){
            multiply = maxCashHandlingFee;
        }
        /**
         * 保存提币申请
         */
        UserCash userCash = new UserCash();
        userCash.setUserId(user.getId());
        userCash.setSystemCoinAccountId(cashForm.getSystemCoinAccountId());
        userCash.setCashNum(cashForm.getCashNum());
        userCash.setCashHandlingFee(multiply);
        userCash.setArrivalQuantity(cashForm.getCashNum().subtract(multiply));
        userCash.setStatus(CashStatus.Under_Review.getStatus());
        userCash.setCashUrl(cashForm.getCashUrl());
        userCashService.saveUserCash(userCash);
    }

    @Override
    public String getToken(Long userId) {
        return null;
    }

    @SuppressWarnings("AlibabaTransactionMustHaveRollback")
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PhoneRegisterVo registerByPhone(PhoneRegisterForm form) {
        String phoneCode = phoneCodeService.getPhoneCode(form.getPhone());
        if(phoneCode == null){
            throw new AiFundException("500","验证码不存在或已过期");
        }
        if(!phoneCode.equals(form.getPhoneCode())){
            throw new AiFundException("500","验证码不正确");
        }
        if(userDao.getByPhone(form.getPhone())!=null){
            //清楚验证码缓存
            phoneCodeService.removePhoneCode(form.getPhone());
            throw new AiFundException("501","该手机号已被注册");
        }
        //清楚验证码缓存
        phoneCodeService.removePhoneCode(form.getPhone());
        //保存用户
        AiUser aiUser = new AiUser();
        BeanUtils.copyProperties(form,aiUser);
        aiUser.setUserIndex(UserEnum.COMMON_USER.getUserIndex());//普通用户
        aiUser.setIsFirstOpen(true);
        userDao.save(aiUser);

        /**
         * 邀请码生成
         */
        String s = InvitationCodeUtil.toSerialCode(aiUser.getId());
        aiUser.setInvitationCode(s);
        //初始积分为0
        aiUser.setIntegration(new BigDecimal(0));
        //VIP等级为0（普通用户)
        aiUser.setVipLever(0);
        userDao.save(aiUser);
        /**
         * 邀请关系保存
         */
        if(form.getInviteCode() != null){
            AiUser parUser = userDao.getByInvitationCode(form.getInviteCode());
            UserInvitation userInvitation = new UserInvitation();
            userInvitation.setUserId(parUser.getId());
            userInvitation.setToUserId(aiUser.getId());
            userInvitationService.save(userInvitation);
        }
        /**
         * token储存
         */
        String token = creatToken(aiUser.getId(),new Date());
        TokenEntity tokenEntity = new TokenEntity();
        tokenEntity.setAiUserId(aiUser.getId());
        tokenEntity.setToken(creatToken(aiUser.getId(),new Date()));
        if(!redisUtil.hset(RedisSetKey.USER_TOKEN.getSetKey(),aiUser.getId()+"",tokenEntity)){
            throw new AiFundException("500","服务器异常","用户token保存失败");
        }
        PhoneRegisterVo registerVo = new PhoneRegisterVo();
        registerVo.setToken(token);
        registerVo.setIsFirstOpen(aiUser.getIsFirstOpen());
        return registerVo;
    }

    @Override
    public AiUser getById(Long id) {
        return userDao.getOne(id);
    }

    @Override
    public Object getAccount(Long userId) {
        return null;
    }

    @Override
    public void updateHeader(String header, Long userId) {
        AiUser user = userDao.getById(userId);
        user.setHeader(header);
        userDao.save(user);
    }

    @Override
    public void updateFirstOpen(Long userId) {
        AiUser user = userDao.getById(userId);
        user.setIsFirstOpen(!user.getIsFirstOpen());
        userDao.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindApi(BindApiForm form, Long userId) {
        /**
         * 查询APIKEY绑定情况
         */
        AiUserBindExchange userBindExchange = userBindExchangeService.getByExchangeIdAndApiKey(form.getExchangeId(), form.getAccessKey());
        if(userBindExchange!=null){
            throw new AiFundException("504","该ACCESS_KEY已经绑定了交易所");
        }
        /**
         * 校验用户是否已经绑定了该交易所
         */
        List<AiUserBindExchange> userBindExchanges = userBindExchangeService.getByUserIdAndExchangeId(userId, form.getExchangeId());
        if(userBindExchanges.size()>0){
            throw new AiFundException("504","目前交易所只能绑定一个API");
        }
        userBindExchange = new AiUserBindExchange();
        userBindExchange.setApiKey(form.getAccessKey());
        userBindExchange.setApiSecret(form.getSecretKey());
        userBindExchange.setAiExchangeId(form.getExchangeId());
        userBindExchange.setAiUserId(userId);
        userBindExchangeService.save(userBindExchange);

        /**
         * 通知MQ用户绑定API
         */
        rabbitTemplate.convertAndSend(MqExchangeEnum.NewApiDirectExchange.getExchangeName(), MqRoutingKeyEnum.NewApiRegister.getRoutingKey(), JSON.toJSONString(userBindExchange));
    }

    @Override
    public void modifyInformation(ModifyInformationForm form, Long userId) {
        AiUser aiUser = userDao.getById(userId);
        BeanUtils.copyProperties(form,aiUser);
        userDao.save(aiUser);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void requestExchangeMan(RequestExchangeManForm form,Long userId) {
        /**
         * 校验交易所是否存在
         */
        AiExchange exchange = exchangeService.getById(form.getExchangeId());
        if(exchange == null){
            throw new AiFundException(CommonEnum.PARAM_VALID_ERROR);
        }
        /**
         * 校验校验类别合法性
         */
        Integer tradeType = form.getTradeType();
        if(tradeType!= TradeTypeEnum.CONTRACT.getType() && tradeType != TradeTypeEnum.SPOT.getType()){
            throw new AiFundException(CommonEnum.PARAM_VALID_ERROR);
        }
        /**
         * 保存策略申请信息
         */
        ExchangeManTactics exchangeManTactics = new ExchangeManTactics();
        BeanUtils.copyProperties(form,exchangeManTactics);
        exchangeManTactics.setUserId(userId);
        exchangeManTactics.setStatus(ExchangeManTacticsStatusEnum.WAIT_AUDIT.getStatus());
        ExchangeManTactics saveTactics = exchangeManTacticsService.save(exchangeManTactics);

        /**
         * 保存策略交易币信息
         */
        List<String> transactionCurrencys = form.getTransactionCurrency();
        for(String transactionCurrency : transactionCurrencys){
              TacticsTransactionCurrency tc = new TacticsTransactionCurrency();
              tc.setTacticsId(saveTactics.getId());
              tc.setTransactionCurrency(transactionCurrency);
              TacticsTransactionCurrency save = tacticsTransactionCurrencyService.save(tc);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void charge(String filePath, BigDecimal chargeNum, Long userId) {
        Charge charge = new Charge();
        charge.setUserId(userId);
        charge.setFilePath(filePath);
        charge.setChargeNum(chargeNum);
        charge.setStatus(ChargeEnum.WAIT_AUDIT.getStatus());
        chargeService.save(charge);
    }

    @Override
    public MyAssetsVo myAssets(Long userId,Long exchangeId) {
//        BigDecimal btc = new BigDecimal(0);
//        BigDecimal ltc = new BigDecimal(0);
//        BigDecimal usdt = new BigDecimal(0);
//        BigDecimal total = new BigDecimal(0);
//        BigDecimal other = new BigDecimal(0);
//        List<AiUserBindExchange> byUserIdAndExchangeId = userBindExchangeService.getByUserIdAndExchangeId(userId, exchangeId);
//        AiExchange exchange = exchangeService.getById(exchangeId);
//        for(AiUserBindExchange userBindExchange : byUserIdAndExchangeId){
//            Grpc.AccountArgs.Builder builder = Grpc.AccountArgs.newBuilder().setApiKey(userBindExchange.getApiKey())
//                    .setExchange(exchange.getExchangeNameEn())
//                    .setSecretKey(userBindExchange.getApiSecret());
//            Grpc.AccountReply account = blockingStub.getAccount(builder.build());
//            Map<String, Grpc.SubAccount> sub = account.getSub();
//            Grpc.SubAccount btcAccount = sub.get("BTC");
//            Grpc.SubAccount ltcAccount = sub.get("LTC");
//            Grpc.SubAccount usdtAccount = sub.get("USDT");
//            if(btcAccount!=null){
//                btc = btc.add(new BigDecimal(btcAccount.getAmount()));
//            }
//            if(ltcAccount!=null){
//                ltc = ltc.add(new BigDecimal(ltcAccount.getAmount()));
//            }
//            if(usdtAccount!=null){
//                usdt = usdt.add(new BigDecimal(usdtAccount.getAmount()));
//            }
//            total =  new BigDecimal(account.getTotal());
//            other = total.min(btc).min(ltc).min(usdt);
//        }
        MyAssetsVo myAssetsVo = new MyAssetsVo();
//        myAssetsVo.setBtc(btc);
//        myAssetsVo.setLtc(ltc);
//        myAssetsVo.setUsdt(usdt);
//        myAssetsVo.setOther(other);
        return myAssetsVo;
    }


    @Override
    public List<GetExchangeManTacticsVo> getExchangeTactics(Long exchangeId) {
        List<GetExchangeManTacticsVo> exchangeMansVos = new ArrayList<>();
        /**
         * 获取所有策略
         */
        List<ExchangeManTactics> allByExchangeIdAndStatus = exchangeManTacticsService.findAllByExchangeIdAndStatus(exchangeId, ExchangeManTacticsStatusEnum.PASS_AUDIT.getStatus());
        for(ExchangeManTactics exchangeManTactics : allByExchangeIdAndStatus){
            GetExchangeManTacticsVo getExchangeManTacticsVo = new GetExchangeManTacticsVo();
            int countByExchangeManTacticsId = followOrderManTacticsService.getCountByExchangeManTacticsId(exchangeManTactics.getId());
            getExchangeManTacticsVo.setUserNumber(countByExchangeManTacticsId);
            BeanUtils.copyProperties(exchangeManTactics,getExchangeManTacticsVo);
            /**
             * 策略币种
             */
            List<TacticsTransactionCurrency> tacticsTransactionCurrencies = tacticsTransactionCurrencyService.getAllByTacticsId(exchangeManTactics.getId());
            List<String> currencyList = new ArrayList<>();
            for(TacticsTransactionCurrency tacticsTransactionCurrency : tacticsTransactionCurrencies){
                currencyList.add(tacticsTransactionCurrency.getTransactionCurrency());
            }
            getExchangeManTacticsVo.setCurrencyList(currencyList);
            exchangeMansVos.add(getExchangeManTacticsVo);
        }

        return exchangeMansVos;
    }


    private String creatToken(Long userId, Date date) {
        /**
         * 获取JWT_SECRET
         */
        String jwtSecret = configService.getJwtSecret();
        /**
         * 获取token失效时长
         */
        Float day = configService.getTokenDay();
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        JwtBuilder builder = Jwts.builder().setHeaderParam("type", "JWT") // 设置header
                .setHeaderParam("alg", "HS256").setIssuedAt(date) // 设置签发时间
                .setExpiration(new Date((long) (date.getTime() + day*24*60*60*1000)))
                .claim("userId",String.valueOf(userId) ) // 设置内容
                .setIssuer("lws")// 设置签发人
                .signWith(signatureAlgorithm, jwtSecret); // 签名，需要算法和key
        String jwt = builder.compact();

        return jwt;
    }
}
